#include "topcvt_object.hpp"

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <sstream>
#include <utility>

static void print_error(const char* format,...)
{
    char error_buf[256] = { 0 };
    va_list ap;
    va_start(ap, format);
    vsnprintf(error_buf, sizeof(error_buf)-1, format, ap);
    va_end(ap);
    std::cerr <<  error_buf << endl;
}

#ifndef TLOG_ERROR
    #define TLOG_ERROR(fmt, ...) print_error(fmt,##__VA_ARGS__)
#endif

#if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdarg.h>
static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size,
    const char* format, va_list ap) {
    int count = -1;
    if (size != 0)
        count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
    if (count == -1)
        count = _vscprintf(format, ap);
    return count;
}

int TOPCVT_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
    const char* format, ...) {
    va_list ap;
    va_start(ap, format);
    const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);
    va_end(ap);
    return count;
}
#endif

// Disable warning C4702 : unreachable code
#if defined(_MSC_VER)
#pragma warning(disable : 4702)
#endif

// This is a walkaround to avoid the static initialization of Object::null.
// kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
// 8 (instead of 4) as a bit of future-proofing.
#if defined(__ARMEL__)
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#else
#define ALIGNAS(byte_alignment)
#endif

#define TOPCVT_ASSERT_UNREACHABLE assert(false)

#define TOPCVT_ASSERT(condition)                                      \
  do {                                                                \
    if (!(condition)) {                                               \
      TLOG_ERROR("assert object failed");                             \
      throw ObjectException("assert object failed");                     \
    }                                                                 \
  } while (0)

#define TOPCVT_FAIL_MESSAGE(message)                                   \
  do {                                                                 \
    TLOG_ERROR("%s",message);                                          \
    throw ObjectException(message);                                       \
  } while (0)

#define TOPCVT_ASSERT_MESSAGE(condition, message)                       \
  do {                                                                  \
    if (!(condition)) {                                                 \
      TOPCVT_FAIL_MESSAGE(message);                                     \
    }                                                                   \
  } while (0)

namespace topcvt 
{
    template <typename T>
    static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
        std::unique_ptr<T> r;
        if (p) {
            r = std::unique_ptr<T>(new T(*p));
        }
        return r;
    }

    Object const& Object::nullSingleton() {
        static Object const nullStatic;
        return nullStatic;
    }

#if !defined(TOPCVT_USE_INT64_DOUBLE_CONVERSION)
    template <typename T, typename U>
    static inline bool InRange(double d, T min, U max) {
        // The casts can lose precision, but we are looking only for
        // an approximate range. Might fail on edge cases though. ~cdunn
        return d >= static_cast<double>(min) && d <= static_cast<double>(max);
    }
#else  // if !defined(TOPCVT_USE_INT64_DOUBLE_CONVERSION)
    static inline double integerToDouble(topcvt::UInt64 value) {
        return static_cast<double>(Int64(value / 2)) * 2.0 +
            static_cast<double>(Int64(value & 1));
    }

    template <typename T> static inline double integerToDouble(T value) {
        return static_cast<double>(value);
    }

    template <typename T, typename U>
    static inline bool InRange(double d, T min, U max) {
        return d >= integerToDouble(min) && d <= integerToDouble(max);
    }
#endif

    /** Duplicates the specified string value.
     * @param value Pointer to the string to duplicate. Must be zero-terminated if
     *              length is "unknown".
     * @param length Length of the value. if equals to unknown, then it will be
     *               computed using strlen(value).
     * @return Pointer on the duplicate instance of string.
     */
    static inline char* duplicateStringValue(const char* value, size_t length) {
        // Avoid an integer overflow in the call to malloc below by limiting length
        // to a sane value.
        if (length >= static_cast<size_t>(Object::maxInt))
            length = Object::maxInt - 1;

        auto newString = static_cast<char*>(malloc(length + 1));
        if (newString == nullptr) {
            throwRuntimeError("in topcvt::Object::duplicateStringValue(): "
                "Failed to allocate string value buffer");
        }
        memcpy(newString, value, length);
        newString[length] = 0;
        return newString;
    }

    /* Record the length as a prefix.
     */
    static inline char* duplicateAndPrefixStringValue(const char* value,
        unsigned int length) {
        // Avoid an integer overflow in the call to malloc below by limiting length
        // to a sane value.
        TOPCVT_ASSERT_MESSAGE(length <= static_cast<unsigned>(Object::maxInt) -
            sizeof(unsigned) - 1U,
            "in topcvt::Object::duplicateAndPrefixStringValue(): "
            "length too big for prefixing");
        size_t actualLength = sizeof(length) + length + 1;
        auto newString = static_cast<char*>(malloc(actualLength));
        if (newString == nullptr) {
            throwRuntimeError("in topcvt::Object::duplicateAndPrefixStringValue(): "
                "Failed to allocate string value buffer");
        }
        *reinterpret_cast<unsigned*>(newString) = length;
        memcpy(newString + sizeof(unsigned), value, length);
        // to avoid buffer over-run accidents by users later
        newString[actualLength - 1U] =  0; 
        return newString;
    }
    inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
        unsigned* length, char const** value) {
        if (!isPrefixed) {
            *length = static_cast<unsigned>(strlen(prefixed));
            *value = prefixed;
        }
        else {
            *length = *reinterpret_cast<unsigned const*>(prefixed);
            *value = prefixed + sizeof(unsigned);
        }
    }
    static inline void releasePrefixedStringValue(char* value) { free(value); }
    static inline void releaseStringValue(char* value, unsigned) { free(value); }

    void throwRuntimeError(String const& msg) {
        throw ObjectException(msg);
    }
    void throwLogicError(String const& msg) {
        throw ObjectException(msg);
    }

    /*! \internal Default constructor initialization must be equivalent to:
     * memset( this, 0, sizeof(Value) )
     * This optimization is used in ValueInternalMap fast allocator.
     */
    Object::Object(ObjectType type) {
        static char const emptyString[] = "";
        initBasic(type);
        switch (type) {
        case nullValue:
            break;
        case intValue:
        case uintValue:
            value_.int_ = 0;
            break;
        case realValue:
            value_.real_ = 0.0;
            break;
        case stringValue:
            value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
            break;
        case arrayValue:
        case objectValue:
            value_.map_ = new ObjectValues();
            break;
        case booleanValue:
            value_.bool_ = false;
            break;
        default:
            TOPCVT_ASSERT_UNREACHABLE;
        }
    }

    Object::Object(Int value) {
        initBasic(intValue);
        value_.int_ = value;
    }

    Object::Object(UInt value) {
        initBasic(uintValue);
        value_.uint_ = value;
    }
#if defined(TOPCVT_HAS_INT64)
    Object::Object(Int64 value) {
        initBasic(intValue);
        value_.int_ = value;
    }
    Object::Object(UInt64 value) {
        initBasic(uintValue);
        value_.uint_ = value;
    }
#endif

    Object::Object(double value) {
        initBasic(realValue);
        value_.real_ = value;
    }

    Object::Object(const char* value) {
        initBasic(stringValue, true);
        TOPCVT_ASSERT_MESSAGE(value != nullptr,"Null Value Passed to Value Constructor");
        value_.string_ = duplicateAndPrefixStringValue(
            value, static_cast<unsigned>(strlen(value)));
    }

    Object::Object(const char* begin, const char* end) {
        initBasic(stringValue, true);
        value_.string_ =
            duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
    }

    Object::Object(const String& value) {
        initBasic(stringValue, true);
        value_.string_ = duplicateAndPrefixStringValue(
            value.data(), static_cast<unsigned>(value.length()));
    }

    Object::Object(const StaticString& value) {
        initBasic(stringValue);
        value_.string_ = const_cast<char*>(value.c_str());
    }

    Object::Object(bool value) {
        initBasic(booleanValue);
        value_.bool_ = value;
    }

    Object::Object(const Object& other) {
        dupPayload(other);
    }

    Object::Object(Object&& other) noexcept {
        initBasic(nullValue);
        swap(other);
    }

    Object::~Object() {
        releasePayload();
        value_.uint_ = 0;
    }

    Object& Object::operator=(const Object& other) {
        Object(other).swap(*this);
        return *this;
    }

    Object& Object::operator=(Object&& other) noexcept {
        other.swap(*this);
        return *this;
    }

    void Object::swapPayload(Object& other) {
        std::swap(bits_, other.bits_);
        std::swap(value_, other.value_);
    }

    void Object::copyPayload(const Object& other) {
        releasePayload();
        dupPayload(other);
    }

    void Object::swap(Object& other) {
        swapPayload(other);
    }

    void Object::copy(const Object& other) {
        copyPayload(other);
    }

    ObjectType Object::type() const {
        return static_cast<ObjectType>(bits_.value_type_);
    }

    int Object::compare(const Object& other) const {
        if (*this < other)  return -1;
        if (*this > other)  return 1;
        return 0;
    }

    bool Object::operator<(const Object& other) const {
        int typeDelta = type() - other.type();
        if (typeDelta)  return typeDelta < 0;

        switch (type()) {
        case nullValue:
            return false;
        case intValue:
            return value_.int_ < other.value_.int_;
        case uintValue:
            return value_.uint_ < other.value_.uint_;
        case realValue:
            return value_.real_ < other.value_.real_;
        case booleanValue:
            return value_.bool_ < other.value_.bool_;
        case stringValue: {
            if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
                return other.value_.string_ != nullptr;
            }
            unsigned this_len;
            unsigned other_len;
            char const* this_str;
            char const* other_str;
            decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
                &this_str);
            decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
                &other_str);
            unsigned min_len = std::min<unsigned>(this_len, other_len);
            TOPCVT_ASSERT(this_str && other_str);
            int comp = memcmp(this_str, other_str, min_len);
            if (comp < 0)
                return true;
            if (comp > 0)
                return false;
            return (this_len < other_len);
        }
        case arrayValue:
        case objectValue: {
            auto thisSize = value_.map_->size();
            auto otherSize = other.value_.map_->size();
            if (thisSize != otherSize)
                return thisSize < otherSize;
            return (*value_.map_) < (*other.value_.map_);
        }
        default:
            TOPCVT_ASSERT_UNREACHABLE;
        }
        return false; // unreachable
    }

    bool Object::operator<=(const Object& other) const { return !(other < *this); }
    bool Object::operator>=(const Object& other) const { return !(*this < other); }
    bool Object::operator>(const Object& other) const { return other < *this; }
    bool Object::operator==(const Object& other) const {
        if (type() != other.type())
            return false;
        switch (type()) {
        case nullValue:
            return true;
        case intValue:
            return value_.int_ == other.value_.int_;
        case uintValue:
            return value_.uint_ == other.value_.uint_;
        case realValue:
            return value_.real_ == other.value_.real_;
        case booleanValue:
            return value_.bool_ == other.value_.bool_;
        case stringValue: {
            if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
                return (value_.string_ == other.value_.string_);
            }
            unsigned this_len;
            unsigned other_len;
            char const* this_str;
            char const* other_str;
            decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
                &this_str);
            decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
                &other_str);
            if (this_len != other_len)
                return false;
            TOPCVT_ASSERT(this_str && other_str);
            int comp = memcmp(this_str, other_str, this_len);
            return comp == 0;
        }
        case arrayValue:
        case objectValue:
            return value_.map_->size() == other.value_.map_->size() &&
                (*value_.map_) == (*other.value_.map_);
        default:
            TOPCVT_ASSERT_UNREACHABLE;
        }
        return false; // unreachable
    }

    bool Object::operator!=(const Object& other) const { return !(*this == other); }

    const char* Object::asCString() const {
        TOPCVT_ASSERT_MESSAGE(type() == stringValue,
            "in topcvt::Object::asCString(): requires stringValue");
        if (value_.string_ == nullptr)
            return nullptr;
        unsigned this_len;
        char const* this_str;
        decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
            &this_str);
        return this_str;
    }

    bool Object::getString(char const** begin, char const** end) const {
        if (type() != stringValue)
            return false;
        if (value_.string_ == nullptr)
            return false;
        unsigned length;
        decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
            begin);
        *end = *begin + length;
        return true;
    }

    string Object::toString()
    {
        switch (type()) {
            case nullValue:
            case stringValue: 
            case booleanValue:
            case intValue:
            case uintValue:
            case realValue:
                return asString();
            case objectValue:
            {
                if (!value_.map_)
                    return string();
                string out;
                out.append("{");
                auto& map = *(this->value_.map_);
                for (auto iter = map.begin(); iter != map.end(); iter++)
                {
                    if (iter != map.begin())
                        out.append(",");
                    out.append(iter->first).append(":").append(iter->second.toString());
                }
                out.append("}");
                return out;
            }
            default: {
                if (!value_.map_)
                    return string();
                string out;
                out.append("[");
                auto& map = *(this->value_.map_);
                for (auto iter = map.begin(); iter != map.end(); iter++)
                {
                    if (iter != map.begin())
                        out.append(",");
                    out.append(iter->second.toString());
                }
                out.append("]");
                return out;
            }
        }
    }

    String Object::asString() const {
        switch (type()) {
        case nullValue:
            return "";
        case stringValue: {
            if (value_.string_ == nullptr)
                return "";
            unsigned this_len;
            char const* this_str;
            decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
                &this_str);
            return String(this_str, this_len);
        }
        case booleanValue:
            return value_.bool_ ? "true" : "false";
        case intValue:
            return ObjectStringUtils::to_string<LargestInt>(value_.int_);
        case uintValue:
            return ObjectStringUtils::to_string<LargestUInt>(value_.uint_);
        case realValue:
            return ObjectStringUtils::to_string<double>(value_.real_);
        default:
            TOPCVT_FAIL_MESSAGE("Type is not convertible to string");
        }
    }

    Object::Int Object::asInt() const {
        switch (type()) {
        case intValue:
            TOPCVT_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
            return Int(value_.int_);
        case uintValue:
            TOPCVT_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
            return Int(value_.uint_);
        case realValue:
            TOPCVT_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
                "double out of Int range");
            return Int(value_.real_);
        case nullValue:
            return 0;
        case booleanValue:
            return value_.bool_ ? 1 : 0;
        default:
            break;
        }
        TOPCVT_FAIL_MESSAGE("Value is not convertible to Int.");
    }

    Object::UInt Object::asUInt() const {
        switch (type()) {
        case intValue:
            TOPCVT_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
            return UInt(value_.int_);
        case uintValue:
            TOPCVT_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
            return UInt(value_.uint_);
        case realValue:
            TOPCVT_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
                "double out of UInt range");
            return UInt(value_.real_);
        case nullValue:
            return 0;
        case booleanValue:
            return value_.bool_ ? 1 : 0;
        default:
            break;
        }
        TOPCVT_FAIL_MESSAGE("Value is not convertible to UInt.");
    }

#if defined(TOPCVT_HAS_INT64)
    Object::Int64 Object::asInt64() const {
        switch (type()) {
        case intValue:
            return Int64(value_.int_);
        case uintValue:
            TOPCVT_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
            return Int64(value_.uint_);
        case realValue:
            TOPCVT_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
                "double out of Int64 range");
            return Int64(value_.real_);
        case nullValue:
            return 0;
        case booleanValue:
            return value_.bool_ ? 1 : 0;
        default:
            break;
        }
        TOPCVT_FAIL_MESSAGE("Value is not convertible to Int64.");
    }

    Object::UInt64 Object::asUInt64() const {
        switch (type()) {
        case intValue:
            TOPCVT_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
            return UInt64(value_.int_);
        case uintValue:
            return UInt64(value_.uint_);
        case realValue:
            TOPCVT_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), "double out of UInt64 range");
            return UInt64(value_.real_);
        case nullValue:
            return 0;
        case booleanValue:
            return value_.bool_ ? 1 : 0;
        default:
            break;
        }
        TOPCVT_FAIL_MESSAGE("Value is not convertible to UInt64.");
    }
#endif 

    LargestInt Object::asLargestInt() const {
#if defined(TOPCVT_NO_INT64)
        return asInt();
#else
        return asInt64();
#endif
    }

    LargestUInt Object::asLargestUInt() const {
#if defined(TOPCVT_NO_INT64)
        return asUInt();
#else
        return asUInt64();
#endif
    }

    double Object::asDouble() const {
        switch (type()) {
        case intValue:
            return static_cast<double>(value_.int_);
        case uintValue:
#if !defined(TOPCVT_USE_INT64_DOUBLE_CONVERSION)
            return static_cast<double>(value_.uint_);
#else  
            return integerToDouble(value_.uint_);
#endif
        case realValue:
            return value_.real_;
        case nullValue:
            return 0.0;
        case booleanValue:
            return value_.bool_ ? 1.0 : 0.0;
        default:
            break;
        }
        TOPCVT_FAIL_MESSAGE("Value is not convertible to double.");
    }

    float Object::asFloat() const {
        switch (type()) {
        case intValue:
            return static_cast<float>(value_.int_);
        case uintValue:
#if !defined(TOPCVT_USE_INT64_DOUBLE_CONVERSION)
            return static_cast<float>(value_.uint_);
#else  // if !defined(TOPCVT_USE_INT64_DOUBLE_CONVERSION)
            // This can fail (silently?) if the value is bigger than MAX_FLOAT.
            return static_cast<float>(integerToDouble(value_.uint_));
#endif // if !defined(TOPCVT_USE_INT64_DOUBLE_CONVERSION)
        case realValue:
            return static_cast<float>(value_.real_);
        case nullValue:
            return 0.0;
        case booleanValue:
            return value_.bool_ ? 1.0F : 0.0F;
        default:
            break;
        }
        TOPCVT_FAIL_MESSAGE("Value is not convertible to float.");
    }

    bool Object::asBool() const {
        switch (type()) {
        case booleanValue:
            return value_.bool_;
        case nullValue:
            return false;
        case intValue:
            return value_.int_ != 0;
        case uintValue:
            return value_.uint_ != 0;
        case realValue: {
            // According to JavaScript language zero or NaN is regarded as false
            const auto value_classification = std::fpclassify(value_.real_);
            return value_classification != FP_ZERO && value_classification != FP_NAN;
        }
        default:
            break;
        }
        TOPCVT_FAIL_MESSAGE("Value is not convertible to bool.");
    }

    bool Object::isConvertibleTo(ObjectType other) const {
        switch (other) {
        case nullValue:
            return (isNumeric() && asDouble() == 0.0) ||
                (type() == booleanValue && !value_.bool_) ||
                (type() == stringValue && asString().empty()) ||
                (type() == arrayValue && value_.map_->empty()) ||
                (type() == objectValue && value_.map_->empty()) ||
                type() == nullValue;
        case intValue:
            return isInt() ||
                (type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
                type() == booleanValue || type() == nullValue;
        case uintValue:
            return isUInt() ||
                (type() == realValue && InRange(value_.real_, 0, maxUInt)) ||
                type() == booleanValue || type() == nullValue;
        case realValue:
            return isNumeric() || type() == booleanValue || type() == nullValue;
        case booleanValue:
            return isNumeric() || type() == booleanValue || type() == nullValue;
        case stringValue:
            return isNumeric() || type() == booleanValue || type() == stringValue ||
                type() == nullValue;
        case arrayValue:
            return type() == arrayValue || type() == nullValue;
        case objectValue:
            return type() == objectValue || type() == nullValue;
        }
        TOPCVT_ASSERT_UNREACHABLE;
        return false;
    }

    ArrayIndex Object::size() const {
        switch (type()) {
        case nullValue:
        case intValue:
        case uintValue:
        case realValue:
        case booleanValue:
        case stringValue:
            return 0;
        case arrayValue: 
        case objectValue:
            return ArrayIndex(value_.map_->size());
        }
        TOPCVT_ASSERT_UNREACHABLE;
        return 0; 
    }

    bool Object::empty() const {
        if (isNull() || isArray() || isObject())
            return size() == 0U;
        return false;
    }

    Object::operator bool() const { return !isNull(); }

    void Object::clear() {
        TOPCVT_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
            type() == objectValue,"in topcvt::Object::clear(): requires complex value");
        switch (type()) {
        case arrayValue:
        case objectValue:
            value_.map_->clear();
            break;
        default:
            break;
        }
    }

    Object& Object::operator[](ArrayIndex index) {
        TOPCVT_ASSERT_MESSAGE( type() == nullValue || type() == arrayValue,
            "in topcvt::Object::operator[](ArrayIndex): requires arrayValue");
        if (type() == nullValue)
            *this = Object(arrayValue);
        string key = ObjectStringUtils::to_string<ArrayIndex>(index);
        auto it = value_.map_->lower_bound(key);
        if (it != value_.map_->end() && (*it).first == key)
            return (*it).second;

        ObjectValues::value_type defaultValue(key, nullSingleton());
        it = value_.map_->insert(it, defaultValue);
        return (*it).second;
    }

    Object& Object::operator[](int index) {
        TOPCVT_ASSERT_MESSAGE( index >= 0,
            "in topcvt::Object::operator[](int index): index cannot be negative");
        return (*this)[ArrayIndex(index)];
    }

    const Object& Object::operator[](ArrayIndex index) const {
        TOPCVT_ASSERT_MESSAGE( type() == nullValue || type() == arrayValue,
            "in topcvt::Object::operator[](ArrayIndex)const: requires arrayValue");
        if (type() == nullValue)
            return nullSingleton();
        string key = ObjectStringUtils::to_string<ArrayIndex>(index);
        ObjectValues::const_iterator it = value_.map_->find(key);
        if (it == value_.map_->end())
            return nullSingleton();
        return (*it).second;
    }

    const Object& Object::operator[](int index) const {
        TOPCVT_ASSERT_MESSAGE( index >= 0,
            "in topcvt::Object::operator[](int index) const: index cannot be negative");
        return (*this)[ArrayIndex(index)];
    }

    void Object::initBasic(ObjectType type, bool allocated) {
        setType(type);
        setIsAllocated(allocated);
        index_ = 0;
    }

    void Object::dupPayload(const Object& other) {
        setType(other.type());
        setIsAllocated(false);
        index_ = other.index_;
        switch (type()) {
        case nullValue:
        case intValue:
        case uintValue:
        case realValue:
        case booleanValue:
            value_ = other.value_;
            break;
        case stringValue:
            if (other.value_.string_ && other.isAllocated()) {
                unsigned len;
                char const* str;
                decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
                    &str);
                value_.string_ = duplicateAndPrefixStringValue(str, len);
                setIsAllocated(true);
            }
            else {
                value_.string_ = other.value_.string_;
            }
            break;
        case arrayValue:
        case objectValue:
            value_.map_ = new ObjectValues(*other.value_.map_);
            break;
        default:
            TOPCVT_ASSERT_UNREACHABLE;
        }
    }

    void Object::releasePayload() {
        switch (type()) {
        case nullValue:
        case intValue:
        case uintValue:
        case realValue:
        case booleanValue:
            break;
        case stringValue:
            if (isAllocated())
                releasePrefixedStringValue(value_.string_);
            break;
        case arrayValue:
        case objectValue:
            delete value_.map_;
            break;
        default:
            TOPCVT_ASSERT_UNREACHABLE;
        }
    }

    // Access an object value by name, create a null member if it does not exist.
    // @pre Type of '*this' is object or null.
    // @param key is null-terminated.
    Object& Object::resolveReference(const string& key) {
        TOPCVT_ASSERT_MESSAGE(
            type() == nullValue || type() == objectValue,
            "in topcvt::Object::resolveReference(): requires objectValue");
        if (type() == nullValue)
            *this = Object(objectValue);
        auto it = value_.map_->lower_bound(key);
        if (it != value_.map_->end() && (*it).first == key)
            return (*it).second;

        ObjectValues::value_type defaultValue(key, nullSingleton());
        it = value_.map_->insert(it, defaultValue);
        Object& value = (*it).second;
        return value;
    }

    Object Object::get(ArrayIndex index, const Object& defaultValue) const {
        const Object* value = &((*this)[index]);
        return value == &nullSingleton() ? defaultValue : *value;
    }

    bool Object::isValidIndex(ArrayIndex index) const { return index < size(); }

    Object const& Object::operator[](const String& key) const {
        Object const* found = find(key);
        if (!found)
            return nullSingleton();
        return *found;
    }

    Object& Object::operator[](const String& key) {
        return resolveReference(key);
    }

    Object& Object::operator[](const StaticString& key) {
        return resolveReference(key.c_str());
    }

    Object& Object::append(const Object& value) { return append(Object(value)); }

    Object& Object::append(Object&& value) {
        TOPCVT_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
            "in topcvt::Object::append: requires arrayValue");
        if (type() == nullValue) {
            *this = Object(arrayValue);
        }
        if (value.type() == nullValue)
        {
            return *this;
        }
        string key = ObjectStringUtils::to_string<ArrayIndex>(size());
        return value_.map_->emplace(key, std::move(value)).first->second;
    }

    Object& Object::push(const Object& value)
    {
        return append(value);
    }

    const Object& Object::fetchArray()
    {
        TOPCVT_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
            "in topcvt::Object::fetchArray(): requires "
            "objectValue or nullValue");
        if (type() == nullValue)
            return nullSingleton();
        if (index_ >= value_.map_->size())
        {
            return nullSingleton();
        }
        return (*this)[index_++];
    }

    Object const* Object::find(const string& key) const {
        TOPCVT_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
            "in topcvt::Object::find(begin, end): requires "
            "objectValue or nullValue");
        if (type() == nullValue)
            return nullptr;
        ObjectValues::const_iterator it = value_.map_->find(key);
        if (it == value_.map_->end())
            return nullptr;
        return &(*it).second;
    }

    Object Object::get(String const& key, Object const& defaultValue) const {
        Object const* found = find(key);
        return !found ? defaultValue : *found;
    }

    String Object::get(const String& key) const
    {
        auto value = (*this)[key];
        return value.asString();
    }

    void Object::set(const string& key, const Object& value)
    {
        (*this)[key] = value;
    }

    void Object::removeMember(const string& key) {
        TOPCVT_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
            "in topcvt::Object::removeMember(): requires objectValue");
        if (type() != nullValue)
            value_.map_->erase(key);
    }

    bool Object::isMember(String const& key) const {
        Object const* value = find(key);
        return nullptr != value;
    }

    Object::Members Object::getMemberNames() const {
        TOPCVT_ASSERT_MESSAGE( type() == nullValue || type() == objectValue,
            "in topcvt::Object::getMemberNames(), value must be objectValue");
        if (type() == nullValue)
            return Object::Members();
        Members members;
        members.reserve(value_.map_->size());
        ObjectValues::const_iterator it = value_.map_->begin();
        ObjectValues::const_iterator itEnd = value_.map_->end();
        for (; it != itEnd; ++it) {
            members.push_back(String((*it).first.data(), (*it).first.length()));
        }
        return members;
    }

    static bool IsIntegral(double d) {
        double integral_part;
        return modf(d, &integral_part) == 0.0;
    }

    bool Object::isNull() const { return type() == nullValue; }
    bool Object::isBool() const { return type() == booleanValue; }

    bool Object::isInt() const {
        switch (type()) {
        case intValue:
#if defined(TOPCVT_HAS_INT64)
            return value_.int_ >= minInt && value_.int_ <= maxInt;
#else
            return true;
#endif
        case uintValue:
            return value_.uint_ <= UInt(maxInt);
        case realValue:
            return value_.real_ >= minInt && value_.real_ <= maxInt &&
                IsIntegral(value_.real_);
        default:
            break;
        }
        return false;
    }

    bool Object::isUInt() const {
        switch (type()) {
        case intValue:
#if defined(TOPCVT_HAS_INT64)
            return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
#else
            return value_.int_ >= 0;
#endif
        case uintValue:
#if defined(TOPCVT_HAS_INT64)
            return value_.uint_ <= maxUInt;
#else
            return true;
#endif
        case realValue:
            return value_.real_ >= 0 && value_.real_ <= maxUInt && IsIntegral(value_.real_);
        default:
            break;
        }
        return false;
    }

    bool Object::isInt64() const {
#if defined(TOPCVT_HAS_INT64)
        switch (type()) {
        case intValue:
            return true;
        case uintValue:
            return value_.uint_ <= UInt64(maxInt64);
        case realValue:
            return value_.real_ >= double(minInt64) &&
                value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
        default:
            break;
        }
#endif
        return false;
    }

    bool Object::isUInt64() const {
#if defined(TOPCVT_HAS_INT64)
        switch (type()) {
        case intValue:
            return value_.int_ >= 0;
        case uintValue:
            return true;
        case realValue:
            return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
        default:
            break;
        }
#endif
        return false;
    }

    bool Object::isIntegral() const {
        switch (type()) {
        case intValue:
        case uintValue:
            return true;
        case realValue:
#if defined(TOPCVT_HAS_INT64)
            return value_.real_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble 
                && IsIntegral(value_.real_);
#else
            return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_);
#endif
        default:
            break;
        }
        return false;
    }

    bool Object::isDouble() const {
        return type() == intValue || type() == uintValue || type() == realValue;
    }

    bool Object::isNumeric() const { return isDouble(); }
    bool Object::isString() const { return type() == stringValue; }
    bool Object::isArray() const { return type() == arrayValue; }
    bool Object::isObject() const { return type() == objectValue; }

    Object::const_iterator Object::begin() const {
        switch (type()) {
        case arrayValue:
        case objectValue:
            if (value_.map_)
                return const_iterator(value_.map_->begin());
            break;
        default:
            break;
        }
        return {};
    }

    Object::const_iterator Object::end() const {
        switch (type()) {
        case arrayValue:
        case objectValue:
            if (value_.map_)
                return const_iterator(value_.map_->end());
            break;
        default:
            break;
        }
        return {};
    }

    Object::iterator Object::begin() {
        switch (type()) {
        case arrayValue:
        case objectValue:
            if (value_.map_)
                return iterator(value_.map_->begin());
            break;
        default:
            break;
        }
        return iterator();
    }

    Object::iterator Object::end() {
        switch (type()) {
        case arrayValue:
        case objectValue:
            if (value_.map_)
                return iterator(value_.map_->end());
            break;
        default:
            break;
        }
        return iterator();
    }

    ObjectIteratorBase::ObjectIteratorBase() : current_() {}

    ObjectIteratorBase::ObjectIteratorBase(
        const Object::ObjectValues::iterator& current)
        : current_(current), isNull_(false) {}

    Object& ObjectIteratorBase::deref() { return current_->second; }
    const Object& ObjectIteratorBase::deref() const { return current_->second; }

    void ObjectIteratorBase::increment() { ++current_; }

    void ObjectIteratorBase::decrement() { --current_; }

    ObjectIteratorBase::difference_type
        ObjectIteratorBase::computeDistance(const SelfType& other) const {
        // Iterator for null value are initialized using the default
        // constructor, which initialize current_ to the default
        // std::map::iterator. As begin() and end() are two instance
        // of the default std::map::iterator, they can not be compared.
        // To allow this, we handle this comparison specifically.
        if (isNull_ && other.isNull_) {
            return 0;
        }

        // Usage of std::distance is not portable (does not compile with Sun Studio 12
        // RogueWave STL,
        // which is the one used by default).
        // Using a portable hand-made version for non random iterator instead:
        //   return difference_type( std::distance( current_, other.current_ ) );
        difference_type myDistance = 0;
        for (Object::ObjectValues::iterator it = current_; it != other.current_;
            ++it) {
            ++myDistance;
        }
        return myDistance;
    }

    bool ObjectIteratorBase::isEqual(const SelfType& other) const {
        if (isNull_) {
            return other.isNull_;
        }
        return current_ == other.current_;
    }

    void ObjectIteratorBase::copy(const SelfType& other) {
        current_ = other.current_;
        isNull_ = other.isNull_;
    }

    Object ObjectIteratorBase::key() const {
        const string czstring = (*current_).first;
        if (czstring.data()) {
            return Object(czstring.data(), czstring.data() + czstring.length());
        }
        return Object(0);
    }

    UInt ObjectIteratorBase::index() const {
        const string czstring = (*current_).first;
        if (!czstring.data())
            return 0;
        return Object::UInt(-1);
    }

    String ObjectIteratorBase::name() const {
        char const* keey;
        char const* end;
        keey = memberName(&end);
        if (!keey)
            return String();
        return String(keey, end);
    }

    //char const* ObjectIteratorBase::memberName() const {
    //    const char* cname = (*current_).first.data();
    //    return cname ? cname : "";
   // }

    char const* ObjectIteratorBase::memberName(char const** end) const {
        const char* cname = (*current_).first.data();
        if (!cname) {
            *end = nullptr;
            return nullptr;
        }
        *end = cname + (*current_).first.length();
        return cname;
    }

    ObjectConstIterator::ObjectConstIterator() = default;

    ObjectConstIterator::ObjectConstIterator(
        const Object::ObjectValues::iterator & current)
        : ObjectIteratorBase(current) {}

    ObjectConstIterator::ObjectConstIterator(ObjectIterator const& other)
        : ObjectIteratorBase(other) {}

    ObjectConstIterator& ObjectConstIterator::
        operator=(const ObjectIteratorBase & other) {
        copy(other);
        return *this;
    }

    ObjectIterator::ObjectIterator() = default;

    ObjectIterator::ObjectIterator(const Object::ObjectValues::iterator & current)
        : ObjectIteratorBase(current) {}

    ObjectIterator::ObjectIterator(const ObjectConstIterator& other)
        : ObjectIteratorBase(other) {
        throwRuntimeError("ConstIterator to Iterator should never be allowed.");
    }

    ObjectIterator::ObjectIterator(const ObjectIterator & other) = default;

    ObjectIterator& ObjectIterator::operator=(const SelfType & other) {
        copy(other);
        return *this;
    }

    ObjectFormat::ObjectFormat()
        : m_fmtLen(0)
    {
        m_level.push(0);
    }

    ObjectFormat::ObjectFormat(uint16_t fmtLen)
        : m_fmtLen(fmtLen)
    {
        m_level.push(0);
    }

    string ObjectFormat::formatObject(Object& object,int fmtLen)
    {
        ObjectFormat fmt(fmtLen);
        return fmt.format(object);
    }

    string ObjectFormat::format(Object& object, bool isflag)
    {
        if (m_fmtLen == 0)
            return object.toString();

        if( !object.isArray() && !object.isObject() )
        {
            formatValue(object.toString());
            return m_buffer;
        }    

        if(isflag)
            formatObjectBegin();
        push();
        auto nameList = object.getMemberNames();
        for (auto& name : nameList)
        {
            auto& obj = object[name];
            if (obj.type() == topcvt::objectValue)
            {
                formatObjectBegin(name);
                push();
                format(obj, 0 );
                pop();
                formatObjectEnd();
            }
            else if (obj.type() == topcvt::arrayValue)
            {
                formatArrayBegin(name);
                push();
                size_t size = obj.size();
                if( size < 100)
                {
                    for (auto iter = obj.begin(); iter != obj.end(); iter++)
                        format(*iter, (*iter).size()>1);
                }
                else
                {
                    m_buffer.append(" The size limit is exceeded");
                }
                pop();
                formatArrayEnd();
            }
            else
            {
                formatValue(name, obj.asString());
            }
        }
        pop();
        if (isflag)
             formatObjectEnd();
        return m_buffer;
    }

    void ObjectFormat::push()
    {
        m_level.push(m_level.top() + 1);
    }

    void ObjectFormat::pop()
    {
        m_level.pop();
    }

    void ObjectFormat::formatObjectBegin(const string& name)
    {
        if (!m_buffer.empty() && 
            (m_buffer.back() != ',' &&  m_buffer.back() != '[' && m_buffer.back() != '{}' && m_buffer.back() != '\n'))
        {
            m_buffer.append(",\n");
        }
        m_buffer.append(count(), 0x20);
        if (!name.empty())
            m_buffer.append(name).append(": ");
        m_buffer.append("{\n");        
    }

    void ObjectFormat::formatObjectEnd()
    {
        if(!m_buffer.empty() && m_buffer.back() != '\n')
        {
            m_buffer.append("\n");
        }
        m_buffer.append(count(), 0x20).append("}");
    }

    void ObjectFormat::formatArrayBegin(const string& name)
    {
        if (!m_buffer.empty() && 
            (m_buffer.back() != ',' &&  m_buffer.back() != '[' && m_buffer.back() != '{}' && m_buffer.back() != '\n'))
        {
            m_buffer.append(",\n");
        }
        m_buffer.append(count(), 0x20);
        m_buffer.append(name).append(": [\n");
    }

    void ObjectFormat::formatArrayEnd()
    {
        if(!m_buffer.empty() && m_buffer.back() != '\n')
        {
            m_buffer.append("\n");
        }
        m_buffer.append(count(), 0x20).append("]");
    }

    void ObjectFormat::formatValue(const string& name, const string& value)
    {
        if (!m_buffer.empty() && 
            (m_buffer.back() != ',' &&  m_buffer.back() != '[' && m_buffer.back() != '{}' && m_buffer.back() != '\n'))
            m_buffer.append(",\n");
        m_buffer.append(count(), 0x20);
        m_buffer.append(name).append(": ").append(value).append("\n");
    }

    void ObjectFormat::formatValue(const string& value)
    {
        if (!m_buffer.empty() && 
            (m_buffer.back() != ',' &&  m_buffer.back() != '[' && m_buffer.back() != '{}' && m_buffer.back() != '\n'))
            m_buffer.append(",\n");
        m_buffer.append(count(), 0x20);
        m_buffer.append(value).append("\n");
    }    

    size_t ObjectFormat::count()
    {
        size_t count = (size_t)m_level.top() * m_fmtLen;
        return count;
    }

    void ObjectUtil::toObject(std::map<string, string>& map, Object& object)
    {
        for (auto it = map.begin(); it != map.end(); it ++)
        {
            object[it->first] = it->second;
        }
    }

    void ObjectUtil::toObject(std::map<string, int>& map, Object& object)
    {
        for (auto it = map.begin(); it != map.end(); it++)
        {
            object[it->first] = Object(it->second);
        }
    }

    void ObjectUtil::toObject(std::list<map<string, string>>& list, Object& object)
    {
        for ( auto it = list.begin(); it != list.end(); it++)
        {
            auto& map = *it;
            Object map_obj;
            ObjectUtil::toObject(map, map_obj);
            object.push(map_obj);
        }
    }

    void ObjectUtil::toObject(std::vector<string>& vec, Object& object)
    {
        for (auto& str : vec)
        {
            object.push(Object(str));
        }
    }

} // namespace topcvt
